//
//  main.c
//  Sqlite3_demo
//
//  Created by Robin on 2017/7/4.
//  Copyright © 2017年 Guohuabing. All rights reserved.
//

#include <stdio.h>
#include <sqlite3.h>

static int callback (void *data, int argc, char *values[],char *columns[]){
    
    printf("callback value : %s\n",data);
    
    for (int i=0; i<argc; i++) {
        printf("%s = %s\n",columns[i],values[i]);
    }
    return 0;
}

void queryUserInfo (sqlite3 *db, sqlite3_stmt *stmt);


int main (int argc, char * argv[]){
    
    sqlite3 *db;
    char *errMsg = NULL;
    int rc;
    
    /*open db*/
    rc = sqlite3_open("testDB.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stdout, "SQL error : %s\n",sqlite3_errmsg(db));
        return 0;
    }
    
//    /*create table*/
//    char *createSql = "CREATE TABLE company ( ID INT PRIMARK KEY NOT NULL ," \
//    "NAME      CHAR(50)     NOT NULL ," \
//    "ADDRESS   TEST         NOT NULL ," \
//    "POSITION  VARCHAR(20)  NOT NULL ," \
//    "SALARY    REAL         NOT NULL ," \
//    "AGE       INT                    );";
//    
//    rc = sqlite3_exec(db, createSql, 0, 0, &errMsg);
//    if (rc != SQLITE_OK) {
//        fprintf(stdout, "SQL error : %s\n",errMsg);
//        sqlite3_free(errMsg);
//        sqlite3_close(db);
//        return 0;
//    }
    
    /*insert data*/
//    char *insertSql = "INSERT INTO company (ID, NAME, POSITION, ADDRESS, SALARY, AGE) VALUES " \
//    "(1, '郭华兵', 'iOS', '西三旗', 17000, 26);" \
//    "INSERT INTO company (ID, NAME, POSITION, ADDRESS, SALARY, AGE) VALUES " \
//    "(2, '于洋', 'iOS', '龙泽', 20000, 27);" \
//    "INSERT INTO company (ID, NAME, POSITION, ADDRESS, SALARY, AGE) VALUES " \
//    "(3, '楼律名', 'CTO', '霍营', 55000, 32);";
//    
////    char *para = "this is 1st para;";
//
//    
//    rc = sqlite3_exec(db, insertSql, 0, 0, &errMsg);
//    if (rc != SQLITE_OK) {
//        fprintf(stdout, "SQL error : %s\n",errMsg);
//        sqlite3_free(errMsg);
//        sqlite3_close(db);
//        return 0;
//    }
//    char *para = "this is 1st para;";
//    
//    /*select sql
//     1.只有在执行查询的sql语句时才会调用回调方法;
//     2.查询到一条记录就会执行一次回调方法.
//     */
//    char *selectSql = "SELECT * FROM company";
//    rc = sqlite3_exec(db, selectSql, callback, para, &errMsg);
//    if (rc != SQLITE_OK) {
//        fprintf(stdout, "SQL error : %s\n",errMsg);
//        sqlite3_free(errMsg);
//        sqlite3_close(db);
//        return 0;
//    }
    
    /*prepare sql (预编译SQL) v2 接口更强大
     1. 参数“sqlite3 * db”, 就是我们调用sqlite3_open(), sqlite3_open_v2() 或者 sqlite3_open16()成功后获取的操作数据库的句柄。数据库连接必须没有被关闭。
     
     　　　　2. zSql是第二个参数, 他的编码格式是UTF-8或UTF-16, 它就是将会被预先编译成字节码的SQL语句。sqlite3_prepare() 和 sqlite3_prepare_v2()接口使用的是UTF-8编码。sqlite3_prepare16() 和 sqlite3_prepare16_v2() 使用的是 UTF-16编码。
     
     　　　　3. nByte是第三个参数，说白了，它就是参数zSql字符串的最大长度。如果nByte是负数，那么zSql的长度不限，如果nByte是正数，zSql的长度则不能超过nByte的数值，超出的部分将不会被预编译。如果nByte是0，那么zSql将不会被预编译。如果你之前学过C语言的话，在C语言中是没有所谓的字符串的，是一个指向字符的指针，后面跟了好多字符，以‘\0’结尾，这就是C语言中的字符串，需要通过指针的移动来遍历字符串的，所以nByte是很有必要的。
     
     　　　　4. *ppStmt 是预编译语句后左边的指针，它可以使用sqlite3_step()执行。在发生错误时，*ppStmt就会被设置为NULL。如果输入的文本不是SQL语句（输入的文本为空字符串或者一行注释）*ppStmt就会被设置为NULL。 sqlite3_finalize()负责释放被编译的SQL语句。
     
     　　　　5. pzTail, 看pzTail的类型就可以看出它是指向指针的指针。pzTail指向谁的指针呢？如他不为NULL的话，它就指向预编译SQL语句的末尾，也就是未预编译SQL语句的首指针。
     */
    char *selectSql = "SELECT * FROM company WHERE NAME = ?;";
    
//    SQLITE_API int sqlite3_prepare_v2(
//                                      sqlite3 *db,            /* Database handle */
//                                      const char *zSql,       /* SQL statement, UTF-8 encoded */
//                                      int nByte,              /* Maximum length of zSql in bytes. */
//                                      sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
//                                      const char **pzTail     /* OUT: Pointer to unused portion of zSql */
//                                      );
    sqlite3_stmt *stmt;

    /*
     sqlite3_stmt 的生命周期 sqlite3_stmt *st
     1. sqlite3_prepare_v2 函数创建sqlite3_stmt(记为 st)对象 (相较于sqlite3_prepare, sqlite3_prepare_v2 功能更强大);
     2. sqlite_bind_*()  给st绑定变量;
     3. sqlite3_step 一次或多次执行SQL语句;
     4. sqlite3_reset() 将st 回滚到上次调用sqlite3_step 的状态
     5. sqlite3_finalize() 析构st对象;
     */
    rc = sqlite3_prepare_v2(db, selectSql, -1, &stmt, 0);
    
    /*execute prepared SQL*/
//    if (rc == SQLITE_OK) {
//        while (sqlite3_step(stmt) == SQLITE_ROW) {
//            int rowNum = sqlite3_column_int(stmt, 0);
//            char *name = (char *)sqlite3_column_text(stmt, 1);
//            char *addr = (char *)sqlite3_column_text(stmt, 2);
//            printf("RowNum %d , name = %s, addr = %s\n",rowNum, name, addr);
//        }
//        sqlite3_finalize(stmt);
//        /*
//         sqlite3_reset(stmt); 重置stmt 到初始状态
//         sqlite3_finalize(stmt); 释放预编译的sql语句
//         */
//    }else{
//        fprintf(stdout, "SQL error : %s\n",errMsg);
//        sqlite3_free(errMsg);
//        sqlite3_close(db);
//        return 0;
//    }
    
    /*sqlite3_bind_*() 变量绑定函数*/
    
    /*
               (1) sqlite3_bind_*()的第一个参数是含有上述占位符预编译后的语句指针，也就是sqlite3_stmt的对象。
     
     　　　　　　(2) sqlite3_bind_*()的第二个参数是SQL语句中参数的索引，例如第一个参数的索引值是1，那么就传1。匿名参数的索引是从1开始往后递增的，而有参数名称的可以通过sqlite3_bind_parameter_index()接口传入参数名称来获取该参数的索引，sqlite3_bind_parameter_index()用法如下，第一个参数是sqlite3_stmt的对象，而后边的参数是SQL参数名称，返回值就是该参数的索引。
     
     int index = sqlite3_bind_parameter_index(statement, "$brandidMin");
     　　　　　　(3) 第三个参数是要绑定的值。
     
     　　　　　　(4) sqlite3_bind_blob(), sqlite3_bind_text()和sqlite3_bind_text16()这三个接口中还有有第四和第五个参数，第四个参数代表第三个参数“绑定值”的字节长度。第五个参数是一个指向内存管理回调函数的指针。
     */
    
//    float salary = 0;
    char name[64];
    printf("Please Input The Name: \n");
    scanf("%s",name);
    
//    printf("name  = %s\n",name);
    if (rc == SQLITE_OK) {
//        sqlite3_bind_double(stmt, 0, salary);
        sqlite3_bind_text(stmt, 1, name, -1, 0);
    }
    
    if (rc != SQLITE_OK) {
        fprintf(stdout, "SQL error === %s\n",errMsg);
        sqlite3_free(errMsg);
        sqlite3_close(db);
        return 0;
    }else{
        queryUserInfo(db, stmt);
    }
    
    sqlite3_close(db);
    
    return 0;
}

// 查询数据库的方法
void queryUserInfo (sqlite3 *db, sqlite3_stmt *stmt){
    
    if (sqlite3_step(stmt) == SQLITE_ROW) {
//        printf("执行查询方法?");

        int rowNum = sqlite3_column_int(stmt, 0);
        char *position = (char *)sqlite3_column_text(stmt, 4);
        char *address = (char *)sqlite3_column_text(stmt, 2);
        
        printf("rowNum = %d, name = %s, address = %s \n",rowNum,position,address);
    }else{
        printf("执行查询方法失败\n");
    }
//    while (sqlite3_step(stmt) == SQLITE_OK) {
//        
//        
//    }
    
    sqlite3_finalize(stmt);

}
